package com.ruoyi.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.base.BaseEntity;
import com.ruoyi.common.constant.CacheKeyConstants;
import com.ruoyi.common.constant.ResultConstants;
import com.ruoyi.common.enums.AmountType;
import com.ruoyi.common.enums.TxnType;
import com.ruoyi.common.exception.BusinessException;
import com.ruoyi.common.support.Convert;
import com.ruoyi.common.utils.BigDecimalUtil;
import com.ruoyi.common.utils.Md5Utils;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.system.domain.WdyDirectReward;
import com.ruoyi.system.domain.WdyRecharge;
import com.ruoyi.system.domain.WdyTxnHistory;
import com.ruoyi.system.domain.WdyUser;
import com.ruoyi.system.dto.RechargeCallback;
import com.ruoyi.system.mapper.WdyRechargeMapper;
import com.ruoyi.system.service.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

/**
 * 充值 服务层实现
 * 
 * @author ruoyi
 * @date 2019-12-15
 */
@Service
public class WdyRechargeServiceImpl extends ServiceImpl<WdyRechargeMapper, WdyRecharge> implements IWdyRechargeService
{
//	public static final String RECHARGE_URL = "http://api.2yem.com/index/unifiedorder?format=json";
//	public static final String APPID = "1053201";
//	public static final String SIGN_KEY = "P1MxMLm3BHgsjtMWX9p6LtGUrJbU7qpZ";
	public static final String ALIPAY = "alipay";
	public static final String VERSION = "v1.1";

	protected static Logger log = LoggerFactory.getLogger(WdyRechargeServiceImpl.class);

	@Value("${2yem.callbackUrl}")
	private String callbackUrl;
	@Value("${2yem.successUrl}")
	private String successUrl;
	@Value("${2yem.errorUrl}")
	private String errorUrl;

	@Autowired
	private IWdyUserService wdyUserService;
	@Autowired
	private IRedisTemplateService redisTemplateService;
	@Autowired
	private IWdyTxnHistoryService wdyTxnHistoryService;

	@Autowired
	private IWdyDirectRewardService wdyDirectRewardService;
	@Autowired
	private IWdyReferrerRewardService wdyReferrerRewardService;

	@Autowired
	protected RedisTemplate redisTemplate;

	@Autowired
	private ISysConfigService sysConfigService;
	/**
     * 查询充值信息
     * 
     * @param id 充值ID
     * @return 充值信息
     */
    @Override
	public WdyRecharge selectWdyRechargeById(Long id)
	{
	    return baseMapper.selectWdyRechargeById(id);
	}
	
	/**
     * 查询充值列表
     * 
     * @param wdyRecharge 充值信息
     * @return 充值集合
     */
	@Override
	public List<WdyRecharge> selectWdyRechargeList(WdyRecharge wdyRecharge)
	{
	    return baseMapper.selectWdyRechargeList(wdyRecharge);
	}
	
    /**
     * 新增充值
     * 
     * @param wdyRecharge 充值信息
     * @return 结果
     */
	@Override
	public int insertWdyRecharge(WdyRecharge wdyRecharge)
	{
	    return baseMapper.insertWdyRecharge(wdyRecharge);
	}
	
	/**
     * 修改充值
     * 
     * @param wdyRecharge 充值信息
     * @return 结果
     */
	@Override
	public int updateWdyRecharge(WdyRecharge wdyRecharge)
	{
	    return baseMapper.updateWdyRecharge(wdyRecharge);
	}

	/**
     * 删除充值对象
     * 
     * @param ids 需要删除的数据ID
     * @return 结果
     */
	@Override
	public int deleteWdyRechargeByIds(String ids)
	{
		return baseMapper.deleteWdyRechargeByIds(Convert.toStrArray(ids));
	}


	@Transactional(rollbackFor = Exception.class)
	@Override
	public Map<String, Object> recharge(WdyRecharge recharge) {
		if(!"1".equals(sysConfigService.selectConfigByKey("recharge_switch"))) {
			throw new BusinessException(ResultConstants.FI1000, "请联系客服");
		}

		BigDecimal rechargeAmount = recharge.getAmount();
		if(rechargeAmount == null) {
			throw new BusinessException(ResultConstants.FI1000, "amount " + MessageUtils.message("not.null"));
		}
		rechargeAmount = BigDecimalUtil.getP2BigDecimal(rechargeAmount);
		recharge.setAmount(rechargeAmount);
		if(rechargeAmount.compareTo(BigDecimal.ZERO) <= 0) {
			throw new BusinessException(ResultConstants.FI1000, "amount " + MessageUtils.message("param.error"));
		}
		String txnId = redisTemplateService.getId(CacheKeyConstants.RECHARGE_ID_TPL);
		recharge.setRechargeId(txnId);
		recharge.setRechargeStatus(WdyRecharge.STATUS_PROCESSING);
		recharge.setAmountType(AmountType.CNN.getCode());
		recharge.setCreateBy(ALIPAY);
		this.save(recharge);

		Map<String, String> paramsMap = new HashMap<>();
        paramsMap.put("return_type", "app");
		paramsMap.put("appid", sysConfigService.selectConfigByKey("recharge_appid"));
		paramsMap.put("pay_type", ALIPAY);
		paramsMap.put("amount", rechargeAmount.toString());
		paramsMap.put("callback_url", callbackUrl);
		paramsMap.put("success_url", successUrl);
		paramsMap.put("error_url", errorUrl);
		paramsMap.put("out_trade_no", txnId);
		paramsMap.put("version", VERSION);

		Set<String> keySet = paramsMap.keySet();
		String[] keyArray = keySet.toArray(new String[keySet.size()]);
		Arrays.sort(keyArray);
		StringBuilder sbSign = new StringBuilder();
		StringBuilder sbParams = new StringBuilder();
		for (String k : keyArray) {
			if (paramsMap.get(k).trim().length() > 0) // 参数值为空，则不参与签名
				sbSign.append(k).append("=").append(paramsMap.get(k).trim()).append("&");
			sbParams.append(k).append("=").append(paramsMap.get(k).trim()).append("&");
		}
		sbSign.append("key=").append(sysConfigService.selectConfigByKey("recharge_key"));
		String sign = Md5Utils.hash(sbSign.toString()).toUpperCase();
		sbParams.append("sign=").append(sign);
		JSONObject payResult = JSON.parseObject(HttpUtils.sendPost(sysConfigService.selectConfigByKey("recharge_url"), sbParams.toString()));
		if(payResult.getIntValue("code") != 200) {
			throw new BusinessException(ResultConstants.EX9999, String.format("支付异常[%s]，请稍后重试", payResult.getIntValue("code")));
		}
		Map<String, Object> data = new HashMap<>();
		data.put("rechargeId", recharge.getRechargeId());
		data.putAll(payResult.getJSONObject("data"));
		data.put("url", payResult.getString("url"));
		return data;
 	}

	@Override
	public BigDecimal getSum(WdyRecharge recharge) {
		return baseMapper.getSum(recharge);
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void rechargeCallback(RechargeCallback callback) {
		Map<String, String> paramsMap = new HashMap<>();
//		paramsMap.put("return_type", "app");
		paramsMap.put("appid", sysConfigService.selectConfigByKey("recharge_appid"));
		paramsMap.put("pay_type", ALIPAY);
		paramsMap.put("amount", callback.getAmount());
		paramsMap.put("amount_true", callback.getAmount_true());
		paramsMap.put("callbacks", callback.getCallbacks());
		paramsMap.put("success_url", callback.getSuccess_url());
		paramsMap.put("error_url", callback.getError_url());
		paramsMap.put("out_trade_no", callback.getOut_trade_no());
		paramsMap.put("out_uid", callback.getOut_uid());

		Set<String> keySet = paramsMap.keySet();
		String[] keyArray = keySet.toArray(new String[keySet.size()]);
		Arrays.sort(keyArray);
		StringBuilder sbSign = new StringBuilder();
		for (String k : keyArray) {
			if (paramsMap.get(k).trim().length() > 0) // 参数值为空，则不参与签名
				sbSign.append(k).append("=").append(paramsMap.get(k).trim()).append("&");
		}
		sbSign.append("key=").append(sysConfigService.selectConfigByKey("recharge_key"));
		String sign = Md5Utils.hash(sbSign.toString()).toUpperCase();

		if(!sign.equals(callback.getSign())) {
			log.info("签名错误:{}", sign);
			throw new BusinessException(ResultConstants.FI1000, "签名错误");
		}

		QueryWrapper<WdyRecharge> rechargeQuery = new QueryWrapper<>();
		rechargeQuery.eq("recharge_id", callback.getOut_trade_no());
		rechargeQuery.eq("recharge_status", WdyRecharge.STATUS_PROCESSING);
		WdyRecharge recharge = this.getOne(rechargeQuery);
		if(recharge == null) {
			throw new BusinessException(ResultConstants.FI1000, "订单不存在或已处理");
		}
		if(RechargeCallback.CODE_SUCCESS.equals(callback.getCallbacks())) {
			QueryWrapper<WdyUser> queryWrapper = new QueryWrapper<>();
			queryWrapper.eq("user_id", recharge.getUserId());
			WdyUser user = wdyUserService.getOne(queryWrapper);
			if(recharge.getAmount().compareTo(new BigDecimal(callback.getAmount())) != 0) {
				throw new BusinessException(ResultConstants.FI1000, "支付金额错误");
			}
			WdyUser updateUser = new WdyUser();
			BigDecimal amountTrue = new BigDecimal(callback.getAmount_true());
			updateUser.setCnnAmount(BigDecimalUtil.add(user.getCnnAmount(), amountTrue));
			updateUser.setVersion(user.getVersion());
			if(!wdyUserService.update(updateUser, queryWrapper)) {
				throw new BusinessException(ResultConstants.FI2007, "系统繁忙，请稍后重试");
			}
			UpdateWrapper<WdyRecharge> updateWrapper = new UpdateWrapper<>();
			updateWrapper.eq("id", recharge.getId());
			updateWrapper.eq("recharge_status", WdyRecharge.STATUS_PROCESSING);
			updateWrapper.set("recharge_status", WdyRecharge.STATUS_SUCCESS);
			updateWrapper.set("amount_true", amountTrue);
			if(!this.update(updateWrapper)) {
				throw new BusinessException(ResultConstants.FI2007, "系统繁忙，请稍后重试");
			}

			WdyTxnHistory txnHistory = new WdyTxnHistory();
			txnHistory.setUserId(user.getUserId());
			txnHistory.setTxnId(recharge.getRechargeId());
			txnHistory.setTxnAmount(amountTrue);
			txnHistory.setTxnType(TxnType.RECHARGE_CNN.getCode());
			txnHistory.setAmountType(TxnType.RECHARGE_CNN.getAmountType().getCode());
			txnHistory.setTxnDesc(TxnType.RECHARGE_CNN.getName());
			wdyTxnHistoryService.save(txnHistory);

			wdyDirectRewardService.reward(user.getUserId(), recharge.getAmount(), recharge.getId(), WdyDirectReward.RECHARGE);
			wdyReferrerRewardService.rewardRecharge(user.getUserId(), recharge.getAmount(), recharge.getId());
		} else {
			UpdateWrapper<WdyRecharge> updateWrapper = new UpdateWrapper<>();
			updateWrapper.eq("id", recharge.getId());
			updateWrapper.eq("recharge_status", WdyRecharge.STATUS_PROCESSING);
			updateWrapper.set("recharge_status", WdyRecharge.STATUS_FAIL);
			if(!this.update(updateWrapper)) {
				throw new BusinessException(ResultConstants.FI2007, "系统繁忙，请稍后重试");
			}
		}

		redisTemplate.delete(CacheKeyConstants.RECHARGE_AMOUNT);
	}

	public static void main(String[] args) {
		//{"amount":"1700.00","amount_true":"1700.00","appid":"1096307","callbacks":"CODE_SUCCESS","error_url":"https://vchub.online/#/mine","out_trade_no":"2009220013150001","out_uid":"","sign":"A35C4F381E789AC3C25A94D6A29AD4F7","success_url":"https://vchub.online/#/mine"}
		//A35C4F381E789AC3C25A94D6A29AD4F7callback_url=https://vchub.online/api/rechargeCallback
		Map<String, String> paramsMap = new HashMap<>();
		paramsMap.put("appid", "1096307");
		paramsMap.put("pay_type", ALIPAY);
		paramsMap.put("amount", "1700.00");
		paramsMap.put("amount_true", "1700.00");
		paramsMap.put("callbacks", "CODE_SUCCESS");
		paramsMap.put("success_url", "https://vchub.online/#/mine");
		paramsMap.put("error_url", "https://vchub.online/#/mine");
		paramsMap.put("out_trade_no", "2009220013150001");
		paramsMap.put("out_uid", "");
//		paramsMap.put("version", VERSION);

		Set<String> keySet = paramsMap.keySet();
		String[] keyArray = keySet.toArray(new String[keySet.size()]);
		Arrays.sort(keyArray);
		StringBuilder sbSign = new StringBuilder();
		for (String k : keyArray) {
			if (paramsMap.get(k).trim().length() > 0) // 参数值为空，则不参与签名
				sbSign.append(k).append("=").append(paramsMap.get(k).trim()).append("&");
		}
		sbSign.append("key=").append("cpOZ6qu8c27WxxNfUfpUGaWPxeaQhiZW");
		String sign = Md5Utils.hash(sbSign.toString()).toUpperCase();
		System.out.println(sign);
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void rechargeAdmin(WdyRecharge recharge) {
		BigDecimal rechargeAmount = recharge.getAmount();
		if(rechargeAmount == null) {
			throw new BusinessException(ResultConstants.FI1000, "amount " + MessageUtils.message("not.null"));
		}
		rechargeAmount = BigDecimalUtil.getP2BigDecimal(rechargeAmount);
		recharge.setAmount(rechargeAmount);
		recharge.setAmountTrue(rechargeAmount);
		if(rechargeAmount.compareTo(BigDecimal.ZERO) <= 0) {
			throw new BusinessException(ResultConstants.FI1000, "amount " + MessageUtils.message("param.error"));
		}

		QueryWrapper<WdyUser> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("user_id", recharge.getUserId());
		queryWrapper.eq("del_flag", BaseEntity.NOT_DELETED);
		WdyUser user = wdyUserService.getOne(queryWrapper);
		WdyUser updateUser = new WdyUser();
		updateUser.setCnnAmount(BigDecimalUtil.add(user.getCnnAmount(), rechargeAmount));
		updateUser.setVersion(user.getVersion());
		if(!wdyUserService.update(updateUser, queryWrapper)) {
			throw new BusinessException(ResultConstants.FI2007, "系统繁忙，请稍后重试");
		}
		String txnId = redisTemplateService.getId(CacheKeyConstants.RECHARGE_ID_TPL);
		recharge.setRechargeId(txnId);
		recharge.setRechargeStatus(WdyRecharge.STATUS_SUCCESS);
		recharge.setAmountType(AmountType.CNN.getCode());
		this.save(recharge);

		WdyTxnHistory txnHistory = new WdyTxnHistory();
		txnHistory.setUserId(user.getUserId());
		txnHistory.setTxnId(txnId);
		txnHistory.setTxnAmount(rechargeAmount);
		txnHistory.setTxnType(TxnType.RECHARGE_CNN.getCode());
		txnHistory.setAmountType(TxnType.RECHARGE_CNN.getAmountType().getCode());
		txnHistory.setTxnDesc(TxnType.RECHARGE_CNN.getName());
		wdyTxnHistoryService.save(txnHistory);

		wdyDirectRewardService.reward(user.getUserId(), rechargeAmount, recharge.getId(), WdyDirectReward.RECHARGE);
		wdyReferrerRewardService.rewardRecharge(user.getUserId(), rechargeAmount, recharge.getId());

		redisTemplate.delete(CacheKeyConstants.RECHARGE_AMOUNT);
	}
}
